﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Win32;
using System.Windows;
using System.Xml;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年7月24日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：快速复制并粘贴一个或多个部件命令。不允许跨页面复制。
    /// ★★说明：关于自定义命令的实现，可参考“NewDocument”类的备注。
    /// 
    /// 特别说明：与Copy相比，这个命令的区别仅在于：
    //　　　　　　①此方法不通过ref参数返回字符串；
    //　　　　　　②此方法支持四个方向，并自动定位插入点（不会更改页面插入点）；
    //　　　　　　③此方法末尾会自动调用Paste命令（不会操作Windows系统剪贴板）。
    /// </summary>
    public static class QuickCopiesCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// ★②，修改静态构造方法名。
        /// </summary>
        static QuickCopiesCommand()//类型构造器
        {
            //★③，修改两个字符串参数名。★④以及第三个参数的类型名。
            routedUICmd = new RoutedUICommand(
                "QuickCopiesCommand",
                "QuickCopiesCommand",
                typeof(QuickCopiesCommand),//创建RoutedUICommand对象
                null);

            //如果需要挂接快捷键，请参考下面这段代码：
            //routedUICmd = new RoutedUICommand(
            //    "SaveDocumentCommand",
            //    "SaveDocumentCommand",
            //    typeof(SaveDocumentCommand),//创建RoutedUICommand对象
            //    new InputGestureCollection() 
            //    { 
            //        //★⑤，修改此处三个参数，以便挂接快捷键。
            //        new KeyGesture(Key.S,ModifierKeys.Control,"Ctrl+S")
            //    });

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //★⑧，修改此方法的实现。

            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null) { e.CanExecute = false; return; }

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null) { e.CanExecute = false; return; }

            //List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();
            //if (selectedWidgets.Count <= 0) { e.CanExecute = false; return; }

            //否则用户可能认为这是Bug。
            //PageEditor peFst = widgets[0].MasterEditor;
            //for (int i = 1; i < widgets.Count; i++)
            //{
            //    if (widgets[i].MasterEditor != peFst)
            //    {
            //        e.CanExecute = false;
            //        return;
            //    }
            //}

            e.CanExecute = true; return;
        }

        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //★⑦，修改此方法的实现。
            LunarMessage.Warning(Execute(e.Parameter as string));
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        /// <param name="widgetsTexts">提供这个参数是不得已，
        /// 目的是返回部件Xml文本中的内容字符串的串连值，以便在数据库中搜索文本。</param>
        /// <param name="copyToClipboard">是否真的复制部件Xml文本到剪贴板中，默认为真。
        /// 这是为了便于重用代码而提供的参数。</param>
        public static string Execute(string directionParameter)
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器";

            List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();
            if (selectedWidgets.Count <= 0) return "　　未选定任何部件。";

            PageEditor peFst = selectedWidgets[0].MasterEditor;
            for (int i = 1; i < selectedWidgets.Count; i++)
            {
                if (selectedWidgets[i].MasterEditor != peFst)
                {
                    return "　　不允许跨页面剪切与复制！";
                }
            }

            bool allAreLinkedLine = true;
            foreach (Widgets.Widget w in selectedWidgets)
            {
                ILinkableLine linkedLine = w as ILinkableLine;
                if (linkedLine == null) { allAreLinkedLine = false; break; }

                if (linkedLine.IsLinked == false) { allAreLinkedLine = false; break; }
            }

            if (allAreLinkedLine)
            {
                MessageBox.Show("　　自动连接线不允许剪切与复制，只能添加或删除！", Globals.AppName,
                        MessageBoxButton.OK, MessageBoxImage.Warning);
                return string.Empty;
            }

            StringBuilder sb = new StringBuilder();

            double minLeft = double.MaxValue;
            double minTop = double.MaxValue;
            double maxRight = 0;
            double maxBottom = 0;

            //不相干的关系线，选定也当没选定处理。
            for (int i1 = selectedWidgets.Count - 1; i1 >= 0; i1--)
            {
                ILinkableLine linkableLine = selectedWidgets[i1] as ILinkableLine;
                if (linkableLine == null || linkableLine.IsLinked == false) continue;

                bool startLinked = false; bool endLinked = false;
                for (int i2 = selectedWidgets.Count - 1; i2 >= 0; i2--)
                {
                    if (linkableLine.StartMasterId == selectedWidgets[i2].Id) { startLinked = true; }

                    if (linkableLine.EndMasterId == selectedWidgets[i2].Id) { endLinked = true; }
                }

                if (startLinked == false || endLinked == false)
                {
                    selectedWidgets.Remove(linkableLine as Widgets.Widget);
                    //选定的某个连接线至少有一个点与选定的所有ICanLinkedWidget都不相干。
                }
            }


            List<ILinkableLine> allLinkedLines = new List<ILinkableLine>();
            List<ILinkableLine> startLinkedLines = new List<ILinkableLine>();
            List<ILinkableLine> endLinkedLines = new List<ILinkableLine>();

            peFst.GetLinkdeLines(selectedWidgets, ref allLinkedLines, ref startLinkedLines, ref endLinkedLines);

            //全相干的关系线，没选定也当选定处理。
            foreach (ILinkableLine linkedLine in allLinkedLines)
            {
                if (selectedWidgets.Contains(linkedLine as Widgets.Widget) == false)
                    selectedWidgets.Add(linkedLine as Widgets.Widget);
            }

            foreach (Widgets.Widget w in selectedWidgets)
            {
                if (w.TopLeft.X < minLeft) minLeft = w.TopLeft.X;

                if (w.TopLeft.Y < minTop) minTop = w.TopLeft.Y;

                double right = w.BottomRight.X;
                if (right > maxRight) maxRight = right;

                double bottom = w.BottomRight.Y;
                if (bottom > maxBottom) maxBottom = bottom;
            }

            //与Copy相比，这个命令的区别仅在于：
            //　　①此方法不通过ref参数返回字符串；
            //　　②此方法支持四个方向，并自动定位插入点（不会更改页面插入点）；
            //　　③此方法末尾会自动调用Paste命令（不会操作Windows系统剪贴板）。

            Point newInsertPoint;
            switch (directionParameter)
            {
                case "Top":
                    {
                        newInsertPoint = new Point(minLeft, minTop - (maxBottom - minTop) - 10);
                        if (newInsertPoint.Y < peFst.EditArea.Top)
                        {
                            return "　　此页面顶部没有足够空间！";
                        }

                        break;
                    }
                case "Left":
                    {
                        newInsertPoint = new Point(minLeft - (maxRight - minLeft) - 10, minTop);
                        if (newInsertPoint.X < peFst.EditArea.Left)
                        {
                            return "　　此页面左侧没有足够空间！";
                        }

                        break;
                    }
                case "Right":
                    {
                        newInsertPoint = new Point(maxRight + 10, minTop);
                        if (newInsertPoint.X + (maxRight - minLeft) > peFst.EditArea.Right)
                        {
                            return "　　此页面右侧没有足够空间！";
                        }

                        break;
                    }
                case "Bottom":
                    {
                        newInsertPoint = new Point(minLeft, maxBottom + 10);
                        if (newInsertPoint.Y + (maxBottom - minTop) > peFst.EditArea.Bottom)
                        {
                            return "　　此页面底部没有足够空间！";
                        }

                        break;
                    }
                default: return string.Format("　　QuickCopies命令不能识别Execute方法参数指定的[{0}]指向。", directionParameter);
            }

            sb.Append("<LunarConcept.Copy Width=\"" + (maxRight - minLeft).ToString() + "\" " +
                "Height=\"" + (maxBottom - minTop).ToString() + "\" >");

            Point baseCopyLeftTop = new Point(minLeft, minTop);

            foreach (Widgets.Widget w in selectedWidgets)
            {
                if (w.XmlData != null)
                {
                    string oldLocation = w.XmlData.GetAttributeValueText("Location");

                    Widgets.LineWidget lw = w as Widgets.LineWidget;
                    if (lw != null)
                    {
                        sb.Append(lw.GetRelativeOuterXml(baseCopyLeftTop));
                    }
                    else
                    {
                        Widgets.ContentWidget cw = w as Widgets.ContentWidget;
                        if (cw != null)
                        {
                            cw.XmlData.SetAttribute("Location",
                                new Point(cw.Location.X - minLeft, cw.Location.Y - minTop).ToString());
                            sb.Append(w.XmlData.OuterXml);
                            w.XmlData.SetAttribute("Location", oldLocation);//还原
                        }
                    }
                }
            }

            sb.Append("</LunarConcept.Copy>");

            string result = Commands.PasteCommand.Execute(sb.ToString(), newInsertPoint);

            return result;
        }

        #endregion
    }
}
